package me.yricky.kaguya.base.lu

import me.yricky.kaguya.base.*
import me.yricky.kaguya.base.Module

/**
 * module内部的一段逻辑的抽象表示
 *
 * [inputSignals] 这段逻辑的输入信号，当这些信号发生变化时，逻辑块的输出可能会发生变化
 * [outputSignals] 这段逻辑的输出信号
 */
sealed class LogicUnit{
    abstract val inputSignals:List<Signal>
    abstract val outputSignals:List<Signal>

    protected fun assignToThis(outWire: NamedWire){
        assert(outWire.assignedIn == null){ "${outWire.name}被重复分配了信号源" }
        outWire.assignedIn = this
    }
}

/**
 * 表示将[input]分配给[output]的逻辑单元
 */
class Assign(
    val input: Signal,
    val output: NamedWire
) : LogicUnit(){
    init {
        assert(input.width == output.width){ "assign:分配给${output.name}的信号位宽不正确" }
        assignToThis(output)
    }

    override val inputSignals: List<Signal> = listOf(input)
    override val outputSignals: List<Wire> = listOf(output)
}

class ModuleUnit(
    val instName:String,
    val inputs: Map<String, NamedSignal>,
    val outputs: Map<String, NamedWire>,
    val innerModule: Module,
) : LogicUnit(){
    init {
        val tmpInputs = inputs.toMutableMap()
        innerModule.io.inputs.forEach {
            val externalSignal = tmpInputs.remove(it.name)
            if(externalSignal == null){
                assert(false){ "模块${innerModule.name}的实例${instName}未指定输入信号${it.name}" }
            } else {
                assert(externalSignal.width == it.width){
                    "模块${innerModule.name}的实例${instName}的输入信号${it.name}预期位宽为${it.width}，实际提供信号${externalSignal.name}的位宽为${externalSignal.width}"
                }
            }
        }
        assert(tmpInputs.isEmpty())

        val tmpOutputs = outputs.toMutableMap()
        innerModule.io.outputs.forEach {
            val externalSignal = tmpOutputs.remove(it.name)
            if(externalSignal == null){
                assert(false){ "模块${innerModule.name}的实例${instName}未指定输出信号${it.name}" }
            }else{
                assert(externalSignal.width == it.width){
                    "模块${innerModule.name}的实例${instName}的输出信号${it.name}预期位宽为${it.width}，实际提供信号${externalSignal.name}的位宽为${externalSignal.width}"
                }
                assignToThis(externalSignal)
            }
        }
    }
    override val inputSignals: List<NamedSignal> = inputs.values.toList()
    override val outputSignals: List<NamedWire> = outputs.values.toList()
}

